#include "app_buffer.h"

/**
 * @brief 初始化缓冲区
 *  创建 结构体 、  数组 、子结构体 、子结构体的数据  开辟堆内存空间
 */
app_buffer_t *app_buffer_init(int total_len)
{
    app_buffer_t *buffer = (app_buffer_t *)malloc(sizeof(app_buffer_t));

    for (int i = 0; i < 2; i++)
    {
        buffer->sub_buffers[i] = malloc(sizeof(app_sub_buffer_t));
        buffer->sub_buffers[i]->data = (char *)malloc(total_len);
        buffer->sub_buffers[i]->total_len = total_len;
    }
    // 确定读写下标
    buffer->read_index = 0;
    buffer->write_index = 1;
    // 初始化锁
    pthread_mutex_init(&buffer->read_lock, NULL);
    pthread_mutex_init(&buffer->swap_lock, NULL);

    // 返回缓冲区指针
    return buffer;
}

/**
 * @brief 写入数据
 * @return  成功0 失败-1
 * // 0  从主缓冲中获得负责写的子缓冲
 *  //1  先判断能不能有空间够写
 *  //2  先把数据长度作为帧头写在当前数据的后面
 *  //3  再写帧体
 *  //4  增加数据长度
 */
int app_buffer_write(app_buffer_t *buffer, char *write_data, uint8_t write_data_len)
{

    pthread_mutex_lock(&buffer->swap_lock);
    // 0  从主缓冲中获得负责写的子缓冲
    app_sub_buffer_t *write_buff = buffer->sub_buffers[buffer->write_index];

    // 1  先判断能不能有空间够写
    int remain_len = write_buff->total_len - write_buff->data_len; // 剩余空间
    if (remain_len < write_data_len + 1)
    {
        pthread_mutex_unlock(&buffer->swap_lock);
        log_error("写入时，缓冲区空间不足!");
        return -1;
    }
    // 2  先把数据长度作为帧头写在当前数据的后面
    write_buff->data[write_buff->data_len] = write_data_len;
    // 3  再写帧体
    memcpy(write_buff->data + write_buff->data_len + 1, write_data, write_data_len);

    // 4  增加数据长度
    write_buff->data_len += write_data_len + 1;
    pthread_mutex_unlock(&buffer->swap_lock);
    return 0;
}

void swap_buffer(app_buffer_t *buffer)
{
    pthread_mutex_lock(&buffer->swap_lock);
    buffer->read_index = buffer->read_index == 0 ? 1 : 0;
    buffer->write_index = buffer->write_index == 0 ? 1 : 0;
    pthread_mutex_unlock(&buffer->swap_lock);
}

/**
 * @brief 读取数据
 * @return   实际读取到的数据长度
 * //  0  从主缓冲中获得负责读的子缓冲
 * //  1   判断是否有数据可读
 * //  1.1 如果没有数据可读  要做分区切换
 * //  1.2 分区读写索引进行交换
 * //  1.3 再次从主缓冲中获得负责读的子缓冲
 * //  1.4 在进行判断是否有数据可读
 * //  1.5  如果还没有数据 直接退出
 * //  有数据
 * //  1  比较传递的读取缓冲区大小 是否大于 要读取的长度
 * //  2  读取数据
 * //  2.1  把要读取的数据 拷贝到传入的读取缓冲区中
 * //  2.2  后面的数据覆盖前面的
 * //  2.3  数据长度减少
 *     3  把实际读取的长度进行返回
 */
int app_buffer_read(app_buffer_t *buffer, char *read_buf, int read_buf_len)
{
    ////////////////// A AAAA
    pthread_mutex_lock(&buffer->read_lock);
    //  * //  0  从主缓冲中获得负责读的子缓冲
    app_sub_buffer_t *sub_read_buff = buffer->sub_buffers[buffer->read_index];
    ////////////////// XXXXXXXXXXX
    //  * //  1   判断是否有数据可读
    if (sub_read_buff->data_len == 0)
    {
        //  * //  1.1 如果没有数据可读  要做分区切换
        //  * //  1.2 分区读写索引进行交换
        swap_buffer(buffer);
        //  * //  1.3 再次从主缓冲中获得负责读的子缓冲
        sub_read_buff = buffer->sub_buffers[buffer->read_index];
        //  * //  1.4 在进行判断是否有数据可读
        if (sub_read_buff->data_len == 0)
        { //  * //  1.5  如果还没有数据 直接退出
            pthread_mutex_unlock(&buffer->read_lock);
            return 0;
        }
    }
    ////////////////// B
    //  * //  有数据
    //  * //  1  比较传递的读取缓冲区大小 是否大于 要读取的长度(顶上帧头 ，首字节)
    int to_read_data_len = sub_read_buff->data[0];
    if (to_read_data_len > read_buf_len)
    {

        pthread_mutex_unlock(&buffer->read_lock);
        log_error("读取缓冲区空间不足");
        return -1;
    }
    ////////////////// C
    //  * //  2  读取数据
    //  * //  2.1  把要读取的数据 拷贝到传入的读取缓冲区中
    memcpy(read_buf, sub_read_buff->data + 1, to_read_data_len);
    //  * //  2.2  后面的数据覆盖前面的
    memmove(sub_read_buff->data, sub_read_buff->data + 1 + to_read_data_len, sub_read_buff->data_len - 1 - to_read_data_len);
    //  * //  2.3  数据长度减少
    sub_read_buff->data_len -= (to_read_data_len + 1);
    //  *     3  把实际读取的长度进行返回
    pthread_mutex_unlock(&buffer->read_lock);

    return to_read_data_len;
}

/**
 * @brief 销毁缓冲区
 */
void app_buffer_destroy(app_buffer_t *buffer)
{
    for (int i = 0; i < 2; i++)
    {
        free(buffer->sub_buffers[i]->data);
        free(buffer->sub_buffers[i]);
    }
    free(buffer);
}